// <expected> -*- C++ -*-

// Copyright The GNU Toolchain Authors.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file include/expected
 *  This is a Standard C++ Library header.
 */

#ifndef _GLIBCXX_EXPECTED
#define _GLIBCXX_EXPECTED

#ifdef _GLIBCXX_SYSHDR
#pragma GCC system_header
#endif

#define __glibcxx_want_expected
#define __glibcxx_want_freestanding_expected
#define __glibcxx_want_constrained_equality
#include <bits/version.h>

#ifdef __cpp_lib_expected // C++ >= 23 && __cpp_concepts >= 202002L
#include <initializer_list>
#include <bits/exception.h>	// exception
#include <bits/invoke.h>	// __invoke
#include <bits/stl_construct.h>	// construct_at
#include <bits/utility.h>	// in_place_t

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

  /**
   * @defgroup expected_values Expected values
   * @addtogroup utilities
   * @since C++23
   * @{
   */

  /// Discriminated union that holds an expected value or an error value.
  /**
   * @since C++23
   */
  template<typename _Tp, typename _Er>
    class expected;

  /// Wrapper type used to pass an error value to a `std::expected`.
  /**
   * @since C++23
   */
  template<typename _Er>
    class unexpected;

  /// Exception thrown by std::expected when the value() is not present.
  /**
   * @since C++23
   */
  template<typename _Er>
    class bad_expected_access;

  template<>
    class bad_expected_access<void> : public exception
    {
    protected:
      bad_expected_access() noexcept { }
      bad_expected_access(const bad_expected_access&) noexcept = default;
      bad_expected_access(bad_expected_access&&) noexcept = default;
      bad_expected_access& operator=(const bad_expected_access&) noexcept = default;
      bad_expected_access& operator=(bad_expected_access&&) noexcept = default;
      ~bad_expected_access() = default;

    public:

      [[nodiscard]]
      const char*
      what() const noexcept override
      { return "bad access to std::expected without expected value"; }
    };

  template<typename _Er>
    class bad_expected_access : public bad_expected_access<void> {
    public:
      explicit
      bad_expected_access(_Er __e) : _M_unex(std::move(__e)) { }

      // XXX const char* what() const noexcept override;

      [[nodiscard]]
      _Er&
      error() & noexcept
      { return _M_unex; }

      [[nodiscard]]
      const _Er&
      error() const & noexcept
      { return _M_unex; }

      [[nodiscard]]
      _Er&&
      error() && noexcept
      { return std::move(_M_unex); }

      [[nodiscard]]
      const _Er&&
      error() const && noexcept
      { return std::move(_M_unex); }

    private:
      _Er _M_unex;
    };

  /// Tag type for constructing unexpected values in a std::expected
  /**
   * @since C++23
   */
  struct unexpect_t
  {
    explicit unexpect_t() = default;
  };

  /// Tag for constructing unexpected values in a std::expected
  /**
   * @since C++23
   */
  inline constexpr unexpect_t unexpect{};

/// @cond undocumented
namespace __expected
{
  template<typename _Tp>
    constexpr bool __is_expected = false;
  template<typename _Tp, typename _Er>
    constexpr bool __is_expected<expected<_Tp, _Er>> = true;

  template<typename _Tp>
    constexpr bool __is_unexpected = false;
  template<typename _Tp>
    constexpr bool __is_unexpected<unexpected<_Tp>> = true;

  template<typename _Fn, typename _Tp>
    using __result = remove_cvref_t<invoke_result_t<_Fn&&, _Tp&&>>;
  template<typename _Fn, typename _Tp>
    using __result_xform = remove_cv_t<invoke_result_t<_Fn&&, _Tp&&>>;
  template<typename _Fn>
    using __result0 = remove_cvref_t<invoke_result_t<_Fn&&>>;
  template<typename _Fn>
    using __result0_xform = remove_cv_t<invoke_result_t<_Fn&&>>;

  template<typename _Er>
    concept __can_be_unexpected
      = is_object_v<_Er> && (!is_array_v<_Er>)
	  && (!__expected::__is_unexpected<_Er>)
	  && (!is_const_v<_Er>) && (!is_volatile_v<_Er>);

  // Tag types for in-place construction from an invocation result.
  struct __in_place_inv { };
  struct __unexpect_inv { };
}
/// @endcond

  template<typename _Er>
    class unexpected
    {
      static_assert( __expected::__can_be_unexpected<_Er> );

    public:
      constexpr unexpected(const unexpected&) = default;
      constexpr unexpected(unexpected&&) = default;

      template<typename _Err = _Er>
	requires (!is_same_v<remove_cvref_t<_Err>, unexpected>)
	  && (!is_same_v<remove_cvref_t<_Err>, in_place_t>)
	  && is_constructible_v<_Er, _Err>
	constexpr explicit
	unexpected(_Err&& __e)
	noexcept(is_nothrow_constructible_v<_Er, _Err>)
	: _M_unex(std::forward<_Err>(__e))
	{ }

      template<typename... _Args>
	requires is_constructible_v<_Er, _Args...>
	constexpr explicit
	unexpected(in_place_t, _Args&&... __args)
	noexcept(is_nothrow_constructible_v<_Er, _Args...>)
	: _M_unex(std::forward<_Args>(__args)...)
	{ }

      template<typename _Up, typename... _Args>
	requires is_constructible_v<_Er, initializer_list<_Up>&, _Args...>
	constexpr explicit
	unexpected(in_place_t, initializer_list<_Up> __il, _Args&&... __args)
	noexcept(is_nothrow_constructible_v<_Er, initializer_list<_Up>&,
					    _Args...>)
	: _M_unex(__il, std::forward<_Args>(__args)...)
	{ }

      constexpr unexpected& operator=(const unexpected&) = default;
      constexpr unexpected& operator=(unexpected&&) = default;


      [[nodiscard]]
      constexpr const _Er&
      error() const & noexcept { return _M_unex; }

      [[nodiscard]]
      constexpr _Er&
      error() & noexcept { return _M_unex; }

      [[nodiscard]]
      constexpr const _Er&&
      error() const && noexcept { return std::move(_M_unex); }

      [[nodiscard]]
      constexpr _Er&&
      error() && noexcept { return std::move(_M_unex); }

      constexpr void
      swap(unexpected& __other) noexcept(is_nothrow_swappable_v<_Er>)
      requires is_swappable_v<_Er>
      {
	using std::swap;
	swap(_M_unex, __other._M_unex);
      }

      template<typename _Err>
	[[nodiscard]]
	friend constexpr bool
	operator==(const unexpected& __x, const unexpected<_Err>& __y)
	{ return __x._M_unex == __y.error(); }

      friend constexpr void
      swap(unexpected& __x, unexpected& __y) noexcept(noexcept(__x.swap(__y)))
      requires is_swappable_v<_Er>
      { __x.swap(__y); }

    private:
      _Er _M_unex;
    };

  template<typename _Er> unexpected(_Er) -> unexpected<_Er>;

/// @cond undocumented
namespace __expected
{
  template<typename _Tp>
    struct _Guard
    {
      static_assert( is_nothrow_move_constructible_v<_Tp> );

      constexpr explicit
      _Guard(_Tp& __x)
      : _M_guarded(__builtin_addressof(__x)), _M_tmp(std::move(__x)) // nothrow
      { std::destroy_at(_M_guarded); }

      constexpr
      ~_Guard()
      {
	if (_M_guarded) [[unlikely]]
	  std::construct_at(_M_guarded, std::move(_M_tmp));
      }

      _Guard(const _Guard&) = delete;
      _Guard& operator=(const _Guard&) = delete;

      constexpr _Tp&&
      release() noexcept
      {
	_M_guarded = nullptr;
	return std::move(_M_tmp);
      }

    private:
      _Tp* _M_guarded;
      _Tp _M_tmp;
    };

  // reinit-expected helper from [expected.object.assign]
  template<typename _Tp, typename _Up, typename _Vp>
    constexpr void
    __reinit(_Tp* __newval, _Up* __oldval, _Vp&& __arg)
    noexcept(is_nothrow_constructible_v<_Tp, _Vp>)
    {
      if constexpr (is_nothrow_constructible_v<_Tp, _Vp>)
	{
	  std::destroy_at(__oldval);
	  std::construct_at(__newval, std::forward<_Vp>(__arg));
	}
      else if constexpr (is_nothrow_move_constructible_v<_Tp>)
	{
	  _Tp __tmp(std::forward<_Vp>(__arg)); // might throw
	  std::destroy_at(__oldval);
	  std::construct_at(__newval, std::move(__tmp));
	}
      else
	{
	  _Guard<_Up> __guard(*__oldval);
	  std::construct_at(__newval, std::forward<_Vp>(__arg)); // might throw
	  __guard.release();
	}
    }

  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 3836. std::expected<bool, E1> conversion constructor
  // expected(const expected<U, G>&) should take precedence over
  // expected(U&&) with operator bool

  // If T is cv bool, remove_cvref_t<U> is not a specialization of expected.
  template<typename _Tp, typename _Up>
    concept __not_constructing_bool_from_expected
      = ! is_same_v<remove_cv_t<_Tp>, bool>
	  || ! __is_expected<remove_cvref_t<_Up>>;
}
/// @endcond

  template<typename _Tp, typename _Er>
    class expected
    {
      static_assert( ! is_reference_v<_Tp> );
      static_assert( ! is_function_v<_Tp> );
      static_assert( ! is_same_v<remove_cv_t<_Tp>, in_place_t> );
      static_assert( ! is_same_v<remove_cv_t<_Tp>, unexpect_t> );
      static_assert( ! __expected::__is_unexpected<remove_cv_t<_Tp>> );
      static_assert( __expected::__can_be_unexpected<_Er> );

      // If T is not cv bool, converts-from-any-cvref<T, expected<U, G>> and
      // is_constructible<unexpected<E>, cv expected<U, G> ref-qual> are false.
      template<typename _Up, typename _Gr, typename _Unex = unexpected<_Er>,
	       typename = remove_cv_t<_Tp>>
	static constexpr bool __cons_from_expected
	  = __or_v<is_constructible<_Tp, expected<_Up, _Gr>&>,
		   is_constructible<_Tp, expected<_Up, _Gr>>,
		   is_constructible<_Tp, const expected<_Up, _Gr>&>,
		   is_constructible<_Tp, const expected<_Up, _Gr>>,
		   is_convertible<expected<_Up, _Gr>&, _Tp>,
		   is_convertible<expected<_Up, _Gr>, _Tp>,
		   is_convertible<const expected<_Up, _Gr>&, _Tp>,
		   is_convertible<const expected<_Up, _Gr>, _Tp>,
		   is_constructible<_Unex, expected<_Up, _Gr>&>,
		   is_constructible<_Unex, expected<_Up, _Gr>>,
		   is_constructible<_Unex, const expected<_Up, _Gr>&>,
		   is_constructible<_Unex, const expected<_Up, _Gr>>
		  >;

      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // If t is cv bool, we know it can be constructed from expected<U, G>,
      // but we don't want to cause the expected(U&&) constructor to be used,
      // so we only check the is_constructible<unexpected<E>, ...> cases.
      template<typename _Up, typename _Gr, typename _Unex>
	static constexpr bool __cons_from_expected<_Up, _Gr, _Unex, bool>
	  = __or_v<is_constructible<_Unex, expected<_Up, _Gr>&>,
		   is_constructible<_Unex, expected<_Up, _Gr>>,
		   is_constructible<_Unex, const expected<_Up, _Gr>&>,
		   is_constructible<_Unex, const expected<_Up, _Gr>>
		  >;

      template<typename _Up, typename _Gr>
	constexpr static bool __explicit_conv
	  = __or_v<__not_<is_convertible<_Up, _Tp>>,
		   __not_<is_convertible<_Gr, _Er>>
		  >;

      template<typename _Up>
	static constexpr bool __same_val
	  = is_same_v<typename _Up::value_type, _Tp>;

      template<typename _Up>
	static constexpr bool __same_err
	  = is_same_v<typename _Up::error_type, _Er>;

    public:
      using value_type = _Tp;
      using error_type = _Er;
      using unexpected_type = unexpected<_Er>;

      template<typename _Up>
	using rebind = expected<_Up, error_type>;

      constexpr
      expected()
      noexcept(is_nothrow_default_constructible_v<_Tp>)
      requires is_default_constructible_v<_Tp>
      : _M_val(), _M_has_value(true)
      { }

      expected(const expected&) = default;

      constexpr
      expected(const expected& __x)
      noexcept(__and_v<is_nothrow_copy_constructible<_Tp>,
		       is_nothrow_copy_constructible<_Er>>)
      requires is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Er>
      && (!is_trivially_copy_constructible_v<_Tp>
	  || !is_trivially_copy_constructible_v<_Er>)
      : _M_has_value(__x._M_has_value)
      {
	if (_M_has_value)
	  std::construct_at(__builtin_addressof(_M_val), __x._M_val);
	else
	  std::construct_at(__builtin_addressof(_M_unex), __x._M_unex);
      }

      expected(expected&&) = default;

      constexpr
      expected(expected&& __x)
      noexcept(__and_v<is_nothrow_move_constructible<_Tp>,
		       is_nothrow_move_constructible<_Er>>)
      requires is_move_constructible_v<_Tp> && is_move_constructible_v<_Er>
      && (!is_trivially_move_constructible_v<_Tp>
	  || !is_trivially_move_constructible_v<_Er>)
      : _M_has_value(__x._M_has_value)
      {
	if (_M_has_value)
	  std::construct_at(__builtin_addressof(_M_val),
			    std::move(__x)._M_val);
	else
	  std::construct_at(__builtin_addressof(_M_unex),
			    std::move(__x)._M_unex);
      }

      template<typename _Up, typename _Gr>
	requires is_constructible_v<_Tp, const _Up&>
	      && is_constructible_v<_Er, const _Gr&>
	      && (!__cons_from_expected<_Up, _Gr>)
	constexpr explicit(__explicit_conv<const _Up&, const _Gr&>)
	expected(const expected<_Up, _Gr>& __x)
	noexcept(__and_v<is_nothrow_constructible<_Tp, const _Up&>,
			 is_nothrow_constructible<_Er, const _Gr&>>)
	: _M_has_value(__x._M_has_value)
	{
	  if (_M_has_value)
	    std::construct_at(__builtin_addressof(_M_val), __x._M_val);
	  else
	    std::construct_at(__builtin_addressof(_M_unex), __x._M_unex);
	}

      template<typename _Up, typename _Gr>
	requires is_constructible_v<_Tp, _Up>
	      && is_constructible_v<_Er, _Gr>
	      && (!__cons_from_expected<_Up, _Gr>)
	constexpr explicit(__explicit_conv<_Up, _Gr>)
	expected(expected<_Up, _Gr>&& __x)
	noexcept(__and_v<is_nothrow_constructible<_Tp, _Up>,
			 is_nothrow_constructible<_Er, _Gr>>)
	: _M_has_value(__x._M_has_value)
	{
	  if (_M_has_value)
	    std::construct_at(__builtin_addressof(_M_val),
			      std::move(__x)._M_val);
	  else
	    std::construct_at(__builtin_addressof(_M_unex),
			      std::move(__x)._M_unex);
	}

      template<typename _Up = remove_cv_t<_Tp>>
	requires (!is_same_v<remove_cvref_t<_Up>, expected>)
	  && (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
	  && is_constructible_v<_Tp, _Up>
	  && (!__expected::__is_unexpected<remove_cvref_t<_Up>>)
	  && __expected::__not_constructing_bool_from_expected<_Tp, _Up>
	constexpr explicit(!is_convertible_v<_Up, _Tp>)
	expected(_Up&& __v)
	noexcept(is_nothrow_constructible_v<_Tp, _Up>)
	: _M_val(std::forward<_Up>(__v)), _M_has_value(true)
	{ }

      template<typename _Gr = _Er>
	requires is_constructible_v<_Er, const _Gr&>
	constexpr explicit(!is_convertible_v<const _Gr&, _Er>)
	expected(const unexpected<_Gr>& __u)
	noexcept(is_nothrow_constructible_v<_Er, const _Gr&>)
	: _M_unex(__u.error()), _M_has_value(false)
	{ }

      template<typename _Gr = _Er>
	requires is_constructible_v<_Er, _Gr>
	constexpr explicit(!is_convertible_v<_Gr, _Er>)
	expected(unexpected<_Gr>&& __u)
	noexcept(is_nothrow_constructible_v<_Er, _Gr>)
	: _M_unex(std::move(__u).error()), _M_has_value(false)
	{ }

      template<typename... _Args>
	requires is_constructible_v<_Tp, _Args...>
	constexpr explicit
	expected(in_place_t, _Args&&... __args)
	noexcept(is_nothrow_constructible_v<_Tp, _Args...>)
	: _M_val(std::forward<_Args>(__args)...), _M_has_value(true)
	{ }

      template<typename _Up, typename... _Args>
	requires is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
	constexpr explicit
	expected(in_place_t, initializer_list<_Up> __il, _Args&&... __args)
	noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&,
					    _Args...>)
	: _M_val(__il, std::forward<_Args>(__args)...), _M_has_value(true)
	{ }

      template<typename... _Args>
	requires is_constructible_v<_Er, _Args...>
	constexpr explicit
	expected(unexpect_t, _Args&&... __args)
	noexcept(is_nothrow_constructible_v<_Er, _Args...>)
	: _M_unex(std::forward<_Args>(__args)...), _M_has_value(false)
	{ }

      template<typename _Up, typename... _Args>
	requires is_constructible_v<_Er, initializer_list<_Up>&, _Args...>
	constexpr explicit
	expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args)
	noexcept(is_nothrow_constructible_v<_Er, initializer_list<_Up>&,
					    _Args...>)
	: _M_unex(__il, std::forward<_Args>(__args)...), _M_has_value(false)
	{ }

      constexpr ~expected() = default;

      constexpr ~expected()
      requires (!is_trivially_destructible_v<_Tp>)
	    || (!is_trivially_destructible_v<_Er>)
      {
	if (_M_has_value)
	  std::destroy_at(__builtin_addressof(_M_val));
	else
	  std::destroy_at(__builtin_addressof(_M_unex));
      }

      // assignment

      expected& operator=(const expected&) = delete;

      constexpr expected&
      operator=(const expected& __x)
      noexcept(__and_v<is_nothrow_copy_constructible<_Tp>,
		       is_nothrow_copy_constructible<_Er>,
		       is_nothrow_copy_assignable<_Tp>,
		       is_nothrow_copy_assignable<_Er>>)
      requires is_copy_assignable_v<_Tp> && is_copy_constructible_v<_Tp>
	    && is_copy_assignable_v<_Er> && is_copy_constructible_v<_Er>
	    && (is_nothrow_move_constructible_v<_Tp>
		|| is_nothrow_move_constructible_v<_Er>)
      {
	if (__x._M_has_value)
	  this->_M_assign_val(__x._M_val);
	else
	  this->_M_assign_unex(__x._M_unex);
	return *this;
      }

      constexpr expected&
      operator=(expected&& __x)
      noexcept(__and_v<is_nothrow_move_constructible<_Tp>,
		       is_nothrow_move_constructible<_Er>,
		       is_nothrow_move_assignable<_Tp>,
		       is_nothrow_move_assignable<_Er>>)
      requires is_move_assignable_v<_Tp> && is_move_constructible_v<_Tp>
	    && is_move_assignable_v<_Er> && is_move_constructible_v<_Er>
	    && (is_nothrow_move_constructible_v<_Tp>
		|| is_nothrow_move_constructible_v<_Er>)
      {
	if (__x._M_has_value)
	  _M_assign_val(std::move(__x._M_val));
	else
	  _M_assign_unex(std::move(__x._M_unex));
	return *this;
      }

      template<typename _Up = remove_cv_t<_Tp>>
	requires (!is_same_v<expected, remove_cvref_t<_Up>>)
	      && (!__expected::__is_unexpected<remove_cvref_t<_Up>>)
	      && is_constructible_v<_Tp, _Up> && is_assignable_v<_Tp&, _Up>
	      && (is_nothrow_constructible_v<_Tp, _Up>
		  || is_nothrow_move_constructible_v<_Tp>
		  || is_nothrow_move_constructible_v<_Er>)
	constexpr expected&
	operator=(_Up&& __v)
	{
	  _M_assign_val(std::forward<_Up>(__v));
	  return *this;
	}

      template<typename _Gr>
	requires is_constructible_v<_Er, const _Gr&>
	      && is_assignable_v<_Er&, const _Gr&>
	      && (is_nothrow_constructible_v<_Er, const _Gr&>
		  || is_nothrow_move_constructible_v<_Tp>
		  || is_nothrow_move_constructible_v<_Er>)
	constexpr expected&
	operator=(const unexpected<_Gr>& __e)
	{
	  _M_assign_unex(__e.error());
	  return *this;
	}

      template<typename _Gr>
	requires is_constructible_v<_Er, _Gr>
	      && is_assignable_v<_Er&, _Gr>
	      && (is_nothrow_constructible_v<_Er, _Gr>
		  || is_nothrow_move_constructible_v<_Tp>
		  || is_nothrow_move_constructible_v<_Er>)
	constexpr expected&
	operator=(unexpected<_Gr>&& __e)
	{
	  _M_assign_unex(std::move(__e).error());
	  return *this;
	}

      // modifiers

      template<typename... _Args>
	requires is_nothrow_constructible_v<_Tp, _Args...>
	constexpr _Tp&
	emplace(_Args&&... __args) noexcept
	{
	  if (_M_has_value)
	    std::destroy_at(__builtin_addressof(_M_val));
	  else
	    {
	      std::destroy_at(__builtin_addressof(_M_unex));
	      _M_has_value = true;
	    }
	  std::construct_at(__builtin_addressof(_M_val),
			    std::forward<_Args>(__args)...);
	  return _M_val;
	}

      template<typename _Up, typename... _Args>
	requires is_nothrow_constructible_v<_Tp, initializer_list<_Up>&,
					    _Args...>
	constexpr _Tp&
	emplace(initializer_list<_Up> __il, _Args&&... __args) noexcept
	{
	  if (_M_has_value)
	    std::destroy_at(__builtin_addressof(_M_val));
	  else
	    {
	      std::destroy_at(__builtin_addressof(_M_unex));
	      _M_has_value = true;
	    }
	  std::construct_at(__builtin_addressof(_M_val),
			    __il, std::forward<_Args>(__args)...);
	  return _M_val;
	}

      // swap
      constexpr void
      swap(expected& __x)
      noexcept(__and_v<is_nothrow_move_constructible<_Tp>,
		       is_nothrow_move_constructible<_Er>,
		       is_nothrow_swappable<_Tp&>,
		       is_nothrow_swappable<_Er&>>)
      requires is_swappable_v<_Tp> && is_swappable_v<_Er>
	    && is_move_constructible_v<_Tp>
	    && is_move_constructible_v<_Er>
	    && (is_nothrow_move_constructible_v<_Tp>
		|| is_nothrow_move_constructible_v<_Er>)
      {
	if (_M_has_value)
	  {
	    if (__x._M_has_value)
	      {
		using std::swap;
		swap(_M_val, __x._M_val);
	      }
	    else
	      this->_M_swap_val_unex(__x);
	  }
	else
	  {
	    if (__x._M_has_value)
	      __x._M_swap_val_unex(*this);
	    else
	      {
		using std::swap;
		swap(_M_unex, __x._M_unex);
	      }
	  }
      }

      // observers

      [[nodiscard]]
      constexpr const _Tp*
      operator->() const noexcept
      {
	__glibcxx_assert(_M_has_value);
	return __builtin_addressof(_M_val);
      }

      [[nodiscard]]
      constexpr _Tp*
      operator->() noexcept
      {
	__glibcxx_assert(_M_has_value);
	return __builtin_addressof(_M_val);
      }

      [[nodiscard]]
      constexpr const _Tp&
      operator*() const & noexcept
      {
	__glibcxx_assert(_M_has_value);
	return _M_val;
      }

      [[nodiscard]]
      constexpr _Tp&
      operator*() & noexcept
      {
	__glibcxx_assert(_M_has_value);
	return _M_val;
      }

      [[nodiscard]]
      constexpr const _Tp&&
      operator*() const && noexcept
      {
	__glibcxx_assert(_M_has_value);
	return std::move(_M_val);
      }

      [[nodiscard]]
      constexpr _Tp&&
      operator*() && noexcept
      {
	__glibcxx_assert(_M_has_value);
	return std::move(_M_val);
      }

      [[nodiscard]]
      constexpr explicit
      operator bool() const noexcept { return _M_has_value; }

      [[nodiscard]]
      constexpr bool has_value() const noexcept { return _M_has_value; }

      constexpr const _Tp&
      value() const &
      {
	static_assert( is_copy_constructible_v<_Er> );
	if (_M_has_value) [[likely]]
	  return _M_val;
	_GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(_M_unex));
      }

      constexpr _Tp&
      value() &
      {
	static_assert( is_copy_constructible_v<_Er> );
	if (_M_has_value) [[likely]]
	  return _M_val;
	const auto& __unex = _M_unex;
	_GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(__unex));
      }

      constexpr const _Tp&&
      value() const &&
      {
	static_assert( is_copy_constructible_v<_Er> );
	static_assert( is_constructible_v<_Er, const _Er&&> );
	if (_M_has_value) [[likely]]
	  return std::move(_M_val);
	_GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(std::move(_M_unex)));
      }

      constexpr _Tp&&
      value() &&
      {
	static_assert( is_copy_constructible_v<_Er> );
	static_assert( is_constructible_v<_Er, _Er&&> );
	if (_M_has_value) [[likely]]
	  return std::move(_M_val);
	_GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(std::move(_M_unex)));
      }

      constexpr const _Er&
      error() const & noexcept
      {
	__glibcxx_assert(!_M_has_value);
	return _M_unex;
      }

      constexpr _Er&
      error() & noexcept
      {
	__glibcxx_assert(!_M_has_value);
	return _M_unex;
      }

      constexpr const _Er&&
      error() const && noexcept
      {
	__glibcxx_assert(!_M_has_value);
	return std::move(_M_unex);
      }

      constexpr _Er&&
      error() && noexcept
      {
	__glibcxx_assert(!_M_has_value);
	return std::move(_M_unex);
      }

      template<typename _Up = remove_cv_t<_Tp>>
	constexpr _Tp
	value_or(_Up&& __v) const &
	noexcept(__and_v<is_nothrow_copy_constructible<_Tp>,
			 is_nothrow_convertible<_Up, _Tp>>)
	{
	  static_assert( is_copy_constructible_v<_Tp> );
	  static_assert( is_convertible_v<_Up, _Tp> );

	  if (_M_has_value)
	    return _M_val;
	  return static_cast<_Tp>(std::forward<_Up>(__v));
	}

      template<typename _Up = remove_cv_t<_Tp>>
	constexpr _Tp
	value_or(_Up&& __v) &&
	noexcept(__and_v<is_nothrow_move_constructible<_Tp>,
			 is_nothrow_convertible<_Up, _Tp>>)
	{
	  static_assert( is_move_constructible_v<_Tp> );
	  static_assert( is_convertible_v<_Up, _Tp> );

	  if (_M_has_value)
	    return std::move(_M_val);
	  return static_cast<_Tp>(std::forward<_Up>(__v));
	}

      template<typename _Gr = _Er>
	constexpr _Er
	error_or(_Gr&& __e) const&
	{
	  static_assert( is_copy_constructible_v<_Er> );
	  static_assert( is_convertible_v<_Gr, _Er> );

	  if (_M_has_value)
	    return std::forward<_Gr>(__e);
	  return _M_unex;
	}

      template<typename _Gr = _Er>
	constexpr _Er
	error_or(_Gr&& __e) &&
	{
	  static_assert( is_move_constructible_v<_Er> );
	  static_assert( is_convertible_v<_Gr, _Er> );

	  if (_M_has_value)
	    return std::forward<_Gr>(__e);
	  return std::move(_M_unex);
	}

      // monadic operations

      template<typename _Fn> requires is_constructible_v<_Er, _Er&>
	constexpr auto
	and_then(_Fn&& __f) &
	{
	  using _Up = __expected::__result<_Fn, _Tp&>;
	  static_assert(__expected::__is_expected<_Up>,
			"the function passed to std::expected<T, E>::and_then "
			"must return a std::expected");
	  static_assert(is_same_v<typename _Up::error_type, _Er>,
			"the function passed to std::expected<T, E>::and_then "
			"must return a std::expected with the same error_type");

	  if (has_value())
	    return std::__invoke(std::forward<_Fn>(__f), _M_val);
	  else
	    return _Up(unexpect, _M_unex);
	}

      template<typename _Fn> requires is_constructible_v<_Er, const _Er&>
	constexpr auto
	and_then(_Fn&& __f) const &
	{
	  using _Up = __expected::__result<_Fn, const _Tp&>;
	  static_assert(__expected::__is_expected<_Up>,
			"the function passed to std::expected<T, E>::and_then "
			"must return a std::expected");
	  static_assert(is_same_v<typename _Up::error_type, _Er>,
			"the function passed to std::expected<T, E>::and_then "
			"must return a std::expected with the same error_type");

	  if (has_value())
	    return std::__invoke(std::forward<_Fn>(__f), _M_val);
	  else
	    return _Up(unexpect, _M_unex);
	}

      template<typename _Fn> requires is_constructible_v<_Er, _Er>
	constexpr auto
	and_then(_Fn&& __f) &&
	{
	  using _Up = __expected::__result<_Fn, _Tp&&>;
	  static_assert(__expected::__is_expected<_Up>,
			"the function passed to std::expected<T, E>::and_then "
			"must return a std::expected");
	  static_assert(is_same_v<typename _Up::error_type, _Er>,
			"the function passed to std::expected<T, E>::and_then "
			"must return a std::expected with the same error_type");

	  if (has_value())
	    return std::__invoke(std::forward<_Fn>(__f), std::move(_M_val));
	  else
	    return _Up(unexpect, std::move(_M_unex));
	}


      template<typename _Fn> requires is_constructible_v<_Er, const _Er>
	constexpr auto
	and_then(_Fn&& __f) const &&
	{
	  using _Up = __expected::__result<_Fn, const _Tp&&>;
	  static_assert(__expected::__is_expected<_Up>,
			"the function passed to std::expected<T, E>::and_then "
			"must return a std::expected");
	  static_assert(is_same_v<typename _Up::error_type, _Er>,
			"the function passed to std::expected<T, E>::and_then "
			"must return a std::expected with the same error_type");

	  if (has_value())
	    return std::__invoke(std::forward<_Fn>(__f), std::move(_M_val));
	  else
	    return _Up(unexpect, std::move(_M_unex));
	}

      template<typename _Fn> requires is_constructible_v<_Tp, _Tp&>
	constexpr auto
	or_else(_Fn&& __f) &
	{
	  using _Gr = __expected::__result<_Fn, _Er&>;
	  static_assert(__expected::__is_expected<_Gr>,
			"the function passed to std::expected<T, E>::or_else "
			"must return a std::expected");
	  static_assert(is_same_v<typename _Gr::value_type, _Tp>,
			"the function passed to std::expected<T, E>::or_else "
			"must return a std::expected with the same value_type");

	  if (has_value())
	    return _Gr(in_place, _M_val);
	  else
	    return std::__invoke(std::forward<_Fn>(__f), _M_unex);
	}

      template<typename _Fn> requires is_constructible_v<_Tp, const _Tp&>
	constexpr auto
	or_else(_Fn&& __f) const &
	{
	  using _Gr = __expected::__result<_Fn, const _Er&>;
	  static_assert(__expected::__is_expected<_Gr>,
			"the function passed to std::expected<T, E>::or_else "
			"must return a std::expected");
	  static_assert(is_same_v<typename _Gr::value_type, _Tp>,
			"the function passed to std::expected<T, E>::or_else "
			"must return a std::expected with the same value_type");

	  if (has_value())
	    return _Gr(in_place, _M_val);
	  else
	    return std::__invoke(std::forward<_Fn>(__f), _M_unex);
	}


      template<typename _Fn> requires is_constructible_v<_Tp, _Tp>
	constexpr auto
	or_else(_Fn&& __f) &&
	{
	  using _Gr = __expected::__result<_Fn, _Er&&>;
	  static_assert(__expected::__is_expected<_Gr>,
			"the function passed to std::expected<T, E>::or_else "
			"must return a std::expected");
	  static_assert(is_same_v<typename _Gr::value_type, _Tp>,
			"the function passed to std::expected<T, E>::or_else "
			"must return a std::expected with the same value_type");

	  if (has_value())
	    return _Gr(in_place, std::move(_M_val));
	  else
	    return std::__invoke(std::forward<_Fn>(__f), std::move(_M_unex));
	}

      template<typename _Fn> requires is_constructible_v<_Tp, const _Tp>
	constexpr auto
	or_else(_Fn&& __f) const &&
	{
	  using _Gr = __expected::__result<_Fn, const _Er&&>;
	  static_assert(__expected::__is_expected<_Gr>,
			"the function passed to std::expected<T, E>::or_else "
			"must return a std::expected");
	  static_assert(is_same_v<typename _Gr::value_type, _Tp>,
			"the function passed to std::expected<T, E>::or_else "
			"must return a std::expected with the same value_type");

	  if (has_value())
	    return _Gr(in_place, std::move(_M_val));
	  else
	    return std::__invoke(std::forward<_Fn>(__f), std::move(_M_unex));
	}

      template<typename _Fn> requires is_constructible_v<_Er, _Er&>
	constexpr auto
	transform(_Fn&& __f) &
	{
	  using _Up = __expected::__result_xform<_Fn, _Tp&>;
	  using _Res = expected<_Up, _Er>;

	  if (has_value())
	    return _Res(__in_place_inv{}, [&]() {
			  return std::__invoke(std::forward<_Fn>(__f),
					       _M_val);
			});
	  else
	    return _Res(unexpect, _M_unex);
	}

      template<typename _Fn> requires is_constructible_v<_Er, const _Er&>
	constexpr auto
	transform(_Fn&& __f) const &
	{
	  using _Up = __expected::__result_xform<_Fn, const _Tp&>;
	  using _Res = expected<_Up, _Er>;

	  if (has_value())
	    return _Res(__in_place_inv{}, [&]() {
			  return std::__invoke(std::forward<_Fn>(__f),
					       _M_val);
			});
	  else
	    return _Res(unexpect, _M_unex);
	}

      template<typename _Fn> requires is_constructible_v<_Er, _Er>
	constexpr auto
	transform(_Fn&& __f) &&
	{
	  using _Up = __expected::__result_xform<_Fn, _Tp>;
	  using _Res = expected<_Up, _Er>;

	  if (has_value())
	    return _Res(__in_place_inv{}, [&]() {
			  return std::__invoke(std::forward<_Fn>(__f),
					       std::move(_M_val));
			});
	  else
	    return _Res(unexpect, std::move(_M_unex));
	}

      template<typename _Fn> requires is_constructible_v<_Er, const _Er>
	constexpr auto
	transform(_Fn&& __f) const &&
	{
	  using _Up = __expected::__result_xform<_Fn, const _Tp>;
	  using _Res = expected<_Up, _Er>;

	  if (has_value())
	    return _Res(__in_place_inv{}, [&]() {
			  return std::__invoke(std::forward<_Fn>(__f),
					       std::move(_M_val));
			});
	  else
	    return _Res(unexpect, std::move(_M_unex));
	}

      template<typename _Fn> requires is_constructible_v<_Tp, _Tp&>
	constexpr auto
	transform_error(_Fn&& __f) &
	{
	  using _Gr = __expected::__result_xform<_Fn, _Er&>;
	  using _Res = expected<_Tp, _Gr>;

	  if (has_value())
	    return _Res(in_place, _M_val);
	  else
	    return _Res(__unexpect_inv{}, [&]() {
			  return std::__invoke(std::forward<_Fn>(__f),
					       _M_unex);
			});
	}

      template<typename _Fn> requires is_constructible_v<_Tp, const _Tp&>
	constexpr auto
	transform_error(_Fn&& __f) const &
	{
	  using _Gr = __expected::__result_xform<_Fn, const _Er&>;
	  using _Res = expected<_Tp, _Gr>;

	  if (has_value())
	    return _Res(in_place, _M_val);
	  else
	    return _Res(__unexpect_inv{}, [&]() {
			  return std::__invoke(std::forward<_Fn>(__f),
					       _M_unex);
			});
	}

      template<typename _Fn> requires is_constructible_v<_Tp, _Tp>
	constexpr auto
	transform_error(_Fn&& __f) &&
	{
	  using _Gr = __expected::__result_xform<_Fn, _Er&&>;
	  using _Res = expected<_Tp, _Gr>;

	  if (has_value())
	    return _Res(in_place, std::move(_M_val));
	  else
	    return _Res(__unexpect_inv{}, [&]() {
			  return std::__invoke(std::forward<_Fn>(__f),
					       std::move(_M_unex));
			});
	}

      template<typename _Fn> requires is_constructible_v<_Tp, const _Tp>
	constexpr auto
	transform_error(_Fn&& __f) const &&
	{
	  using _Gr = __expected::__result_xform<_Fn, const _Er&&>;
	  using _Res = expected<_Tp, _Gr>;

	  if (has_value())
	    return _Res(in_place, std::move(_M_val));
	  else
	    return _Res(__unexpect_inv{}, [&]() {
			  return std::__invoke(std::forward<_Fn>(__f),
					       std::move(_M_unex));
			});
	}

      // equality operators

      template<typename _Up, typename _Er2>
	requires (!is_void_v<_Up>)
	  && requires (const _Tp& __t, const _Up& __u,
		       const _Er& __e, const _Er2& __e2) {
	    { __t == __u } -> convertible_to<bool>;
	    { __e == __e2 } -> convertible_to<bool>;
	  }
	friend constexpr bool
	operator==(const expected& __x, const expected<_Up, _Er2>& __y)
	noexcept(noexcept(bool(*__x == *__y))
		  && noexcept(bool(__x.error() == __y.error())))
	{
	  if (__x.has_value())
	    return __y.has_value() && bool(*__x == *__y);
	  else
	    return !__y.has_value() && bool(__x.error() == __y.error());
	}

      template<typename _Up>
	requires (!__expected::__is_expected<_Up>)
	  && requires (const _Tp& __t, const _Up& __u) {
	    { __t == __u } -> convertible_to<bool>;
	  }
	friend constexpr bool
	operator==(const expected& __x, const _Up& __v)
	noexcept(noexcept(bool(*__x == __v)))
	{ return __x.has_value() && bool(*__x == __v); }

      template<typename _Er2>
	requires requires (const _Er& __e, const _Er2& __e2) {
	  { __e == __e2 } -> convertible_to<bool>;
	}
	friend constexpr bool
	operator==(const expected& __x, const unexpected<_Er2>& __e)
	noexcept(noexcept(bool(__x.error() == __e.error())))
	{ return !__x.has_value() && bool(__x.error() == __e.error()); }

      friend constexpr void
      swap(expected& __x, expected& __y)
      noexcept(noexcept(__x.swap(__y)))
      requires requires {__x.swap(__y);}
      { __x.swap(__y); }

    private:
      template<typename, typename> friend class expected;

      template<typename _Vp>
	constexpr void
	_M_assign_val(_Vp&& __v)
	{
	  if (_M_has_value)
	    _M_val = std::forward<_Vp>(__v);
	  else
	    {
	      __expected::__reinit(__builtin_addressof(_M_val),
				   __builtin_addressof(_M_unex),
				   std::forward<_Vp>(__v));
	      _M_has_value = true;
	    }
	}

      template<typename _Vp>
	constexpr void
	_M_assign_unex(_Vp&& __v)
	{
	  if (_M_has_value)
	    {
	      __expected::__reinit(__builtin_addressof(_M_unex),
				   __builtin_addressof(_M_val),
				   std::forward<_Vp>(__v));
	      _M_has_value = false;
	    }
	  else
	    _M_unex = std::forward<_Vp>(__v);
	}

      // Swap two expected objects when only one has a value.
      // Precondition: this->_M_has_value && !__rhs._M_has_value
      constexpr void
      _M_swap_val_unex(expected& __rhs)
      noexcept(__and_v<is_nothrow_move_constructible<_Er>,
		       is_nothrow_move_constructible<_Tp>>)
      {
	if constexpr (is_nothrow_move_constructible_v<_Er>)
	  {
	    __expected::_Guard<_Er> __guard(__rhs._M_unex);
	    std::construct_at(__builtin_addressof(__rhs._M_val),
			      std::move(_M_val)); // might throw
	    __rhs._M_has_value = true;
	    std::destroy_at(__builtin_addressof(_M_val));
	    std::construct_at(__builtin_addressof(_M_unex),
			      __guard.release());
	    _M_has_value = false;
	  }
	else
	  {
	    __expected::_Guard<_Tp> __guard(_M_val);
	    std::construct_at(__builtin_addressof(_M_unex),
			      std::move(__rhs._M_unex)); // might throw
	    _M_has_value = false;
	    std::destroy_at(__builtin_addressof(__rhs._M_unex));
	    std::construct_at(__builtin_addressof(__rhs._M_val),
			      __guard.release());
	    __rhs._M_has_value = true;
	  }
      }

      using __in_place_inv = __expected::__in_place_inv;
      using __unexpect_inv = __expected::__unexpect_inv;

      template<typename _Fn>
	explicit constexpr
	expected(__in_place_inv, _Fn&& __fn)
	: _M_val(std::forward<_Fn>(__fn)()), _M_has_value(true)
	{ }

      template<typename _Fn>
	explicit constexpr
	expected(__unexpect_inv, _Fn&& __fn)
	: _M_unex(std::forward<_Fn>(__fn)()), _M_has_value(false)
	{ }

      union {
	remove_cv_t<_Tp> _M_val;
	_Er _M_unex;
      };

      bool _M_has_value;
    };

  // Partial specialization for std::expected<cv void, E>
  template<typename _Tp, typename _Er> requires is_void_v<_Tp>
    class expected<_Tp, _Er>
    {
      static_assert( __expected::__can_be_unexpected<_Er> );

      template<typename _Up, typename _Err, typename _Unex = unexpected<_Er>>
	static constexpr bool __cons_from_expected
	  = __or_v<is_constructible<_Unex, expected<_Up, _Err>&>,
		   is_constructible<_Unex, expected<_Up, _Err>>,
		   is_constructible<_Unex, const expected<_Up, _Err>&>,
		   is_constructible<_Unex, const expected<_Up, _Err>>
		  >;

      template<typename _Up>
	static constexpr bool __same_val
	  = is_same_v<typename _Up::value_type, _Tp>;

      template<typename _Up>
	static constexpr bool __same_err
	  = is_same_v<typename _Up::error_type, _Er>;

    public:
      using value_type = _Tp;
      using error_type = _Er;
      using unexpected_type = unexpected<_Er>;

      template<typename _Up>
	using rebind = expected<_Up, error_type>;

      constexpr
      expected() noexcept
      : _M_void(), _M_has_value(true)
      { }

      expected(const expected&) = default;

      constexpr
      expected(const expected& __x)
      noexcept(is_nothrow_copy_constructible_v<_Er>)
      requires is_copy_constructible_v<_Er>
	    && (!is_trivially_copy_constructible_v<_Er>)
      : _M_void(), _M_has_value(__x._M_has_value)
      {
	if (!_M_has_value)
	  std::construct_at(__builtin_addressof(_M_unex), __x._M_unex);
      }

      expected(expected&&) = default;

      constexpr
      expected(expected&& __x)
      noexcept(is_nothrow_move_constructible_v<_Er>)
      requires is_move_constructible_v<_Er>
	    && (!is_trivially_move_constructible_v<_Er>)
      : _M_void(), _M_has_value(__x._M_has_value)
      {
	if (!_M_has_value)
	  std::construct_at(__builtin_addressof(_M_unex),
			    std::move(__x)._M_unex);
      }

      template<typename _Up, typename _Gr>
	requires is_void_v<_Up>
	      && is_constructible_v<_Er, const _Gr&>
	      && (!__cons_from_expected<_Up, _Gr>)
	constexpr explicit(!is_convertible_v<const _Gr&, _Er>)
	expected(const expected<_Up, _Gr>& __x)
	noexcept(is_nothrow_constructible_v<_Er, const _Gr&>)
	: _M_void(), _M_has_value(__x._M_has_value)
	{
	  if (!_M_has_value)
	    std::construct_at(__builtin_addressof(_M_unex), __x._M_unex);
	}

      template<typename _Up, typename _Gr>
	requires is_void_v<_Up>
	      && is_constructible_v<_Er, _Gr>
	      && (!__cons_from_expected<_Up, _Gr>)
	constexpr explicit(!is_convertible_v<_Gr, _Er>)
	expected(expected<_Up, _Gr>&& __x)
	noexcept(is_nothrow_constructible_v<_Er, _Gr>)
	: _M_void(), _M_has_value(__x._M_has_value)
	{
	  if (!_M_has_value)
	    std::construct_at(__builtin_addressof(_M_unex),
			      std::move(__x)._M_unex);
	}

      template<typename _Gr = _Er>
	requires is_constructible_v<_Er, const _Gr&>
	constexpr explicit(!is_convertible_v<const _Gr&, _Er>)
	expected(const unexpected<_Gr>& __u)
	noexcept(is_nothrow_constructible_v<_Er, const _Gr&>)
	: _M_unex(__u.error()), _M_has_value(false)
	{ }

      template<typename _Gr = _Er>
	requires is_constructible_v<_Er, _Gr>
	constexpr explicit(!is_convertible_v<_Gr, _Er>)
	expected(unexpected<_Gr>&& __u)
	noexcept(is_nothrow_constructible_v<_Er, _Gr>)
	: _M_unex(std::move(__u).error()), _M_has_value(false)
	{ }

      constexpr explicit
      expected(in_place_t) noexcept
      : expected()
      { }

      template<typename... _Args>
	requires is_constructible_v<_Er, _Args...>
	constexpr explicit
	expected(unexpect_t, _Args&&... __args)
	noexcept(is_nothrow_constructible_v<_Er, _Args...>)
	: _M_unex(std::forward<_Args>(__args)...), _M_has_value(false)
	{ }

      template<typename _Up, typename... _Args>
	requires is_constructible_v<_Er, initializer_list<_Up>&, _Args...>
	constexpr explicit
	expected(unexpect_t, initializer_list<_Up> __il, _Args&&... __args)
	noexcept(is_nothrow_constructible_v<_Er, initializer_list<_Up>&,
					    _Args...>)
	: _M_unex(__il, std::forward<_Args>(__args)...), _M_has_value(false)
	{ }

      constexpr ~expected() = default;

      constexpr ~expected() requires (!is_trivially_destructible_v<_Er>)
      {
	if (!_M_has_value)
	  std::destroy_at(__builtin_addressof(_M_unex));
      }

      // assignment

      expected& operator=(const expected&) = delete;

      constexpr expected&
      operator=(const expected& __x)
      noexcept(__and_v<is_nothrow_copy_constructible<_Er>,
		       is_nothrow_copy_assignable<_Er>>)
      requires is_copy_constructible_v<_Er>
	    && is_copy_assignable_v<_Er>
      {
	if (__x._M_has_value)
	  emplace();
	else
	  _M_assign_unex(__x._M_unex);
	return *this;
      }

      constexpr expected&
      operator=(expected&& __x)
      noexcept(__and_v<is_nothrow_move_constructible<_Er>,
		       is_nothrow_move_assignable<_Er>>)
      requires is_move_constructible_v<_Er>
	    && is_move_assignable_v<_Er>
      {
	if (__x._M_has_value)
	  emplace();
	else
	  _M_assign_unex(std::move(__x._M_unex));
	return *this;
      }

      template<typename _Gr>
	requires is_constructible_v<_Er, const _Gr&>
	      && is_assignable_v<_Er&, const _Gr&>
	constexpr expected&
	operator=(const unexpected<_Gr>& __e)
	{
	  _M_assign_unex(__e.error());
	  return *this;
	}

      template<typename _Gr>
	requires is_constructible_v<_Er, _Gr>
	      && is_assignable_v<_Er&, _Gr>
	constexpr expected&
	operator=(unexpected<_Gr>&& __e)
	{
	  _M_assign_unex(std::move(__e.error()));
	  return *this;
	}

      // modifiers

      constexpr void
      emplace() noexcept
      {
	if (!_M_has_value)
	  {
	    std::destroy_at(__builtin_addressof(_M_unex));
	    _M_has_value = true;
	  }
      }

      // swap
      constexpr void
      swap(expected& __x)
      noexcept(__and_v<is_nothrow_swappable<_Er&>,
		       is_nothrow_move_constructible<_Er>>)
      requires is_swappable_v<_Er> && is_move_constructible_v<_Er>
      {
	if (_M_has_value)
	  {
	    if (!__x._M_has_value)
	      {
		std::construct_at(__builtin_addressof(_M_unex),
				  std::move(__x._M_unex)); // might throw
		std::destroy_at(__builtin_addressof(__x._M_unex));
		_M_has_value = false;
		__x._M_has_value = true;
	      }
	  }
	else
	  {
	    if (__x._M_has_value)
	      {
		std::construct_at(__builtin_addressof(__x._M_unex),
				  std::move(_M_unex)); // might throw
		std::destroy_at(__builtin_addressof(_M_unex));
		_M_has_value = true;
		__x._M_has_value = false;
	      }
	    else
	      {
		using std::swap;
		swap(_M_unex, __x._M_unex);
	      }
	  }
      }

      // observers

      [[nodiscard]]
      constexpr explicit
      operator bool() const noexcept { return _M_has_value; }

      [[nodiscard]]
      constexpr bool has_value() const noexcept { return _M_has_value; }

      constexpr void
      operator*() const noexcept { __glibcxx_assert(_M_has_value); }

      constexpr void
      value() const&
      {
	static_assert( is_copy_constructible_v<_Er> );
	if (_M_has_value) [[likely]]
	  return;
	_GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(_M_unex));
      }

      constexpr void
      value() &&
      {
	static_assert( is_copy_constructible_v<_Er> );
	if (_M_has_value) [[likely]]
	  return;
	_GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(std::move(_M_unex)));
      }

      constexpr const _Er&
      error() const & noexcept
      {
	__glibcxx_assert(!_M_has_value);
	return _M_unex;
      }

      constexpr _Er&
      error() & noexcept
      {
	__glibcxx_assert(!_M_has_value);
	return _M_unex;
      }

      constexpr const _Er&&
      error() const && noexcept
      {
	__glibcxx_assert(!_M_has_value);
	return std::move(_M_unex);
      }

      constexpr _Er&&
      error() && noexcept
      {
	__glibcxx_assert(!_M_has_value);
	return std::move(_M_unex);
      }

      template<typename _Gr = _Er>
	constexpr _Er
	error_or(_Gr&& __e) const&
	{
	  static_assert( is_copy_constructible_v<_Er> );
	  static_assert( is_convertible_v<_Gr, _Er> );

	  if (_M_has_value)
	    return std::forward<_Gr>(__e);
	  return _M_unex;
	}

      template<typename _Gr = _Er>
	constexpr _Er
	error_or(_Gr&& __e) &&
	{
	  static_assert( is_move_constructible_v<_Er> );
	  static_assert( is_convertible_v<_Gr, _Er> );

	  if (_M_has_value)
	    return std::forward<_Gr>(__e);
	  return std::move(_M_unex);
	}

      // monadic operations

      template<typename _Fn> requires is_constructible_v<_Er, _Er&>
	constexpr auto
	and_then(_Fn&& __f) &
	{
	  using _Up = __expected::__result0<_Fn>;
	  static_assert(__expected::__is_expected<_Up>);
	  static_assert(is_same_v<typename _Up::error_type, _Er>);

	  if (has_value())
	    return std::__invoke(std::forward<_Fn>(__f));
	  else
	    return _Up(unexpect, _M_unex);
	}

     template<typename _Fn> requires is_constructible_v<_Er, const _Er&>
	constexpr auto
	and_then(_Fn&& __f) const &
	{
	  using _Up = __expected::__result0<_Fn>;
	  static_assert(__expected::__is_expected<_Up>);
	  static_assert(is_same_v<typename _Up::error_type, _Er>);

	  if (has_value())
	    return std::__invoke(std::forward<_Fn>(__f));
	  else
	    return _Up(unexpect, _M_unex);
	}

      template<typename _Fn> requires is_constructible_v<_Er, _Er>
	constexpr auto
	and_then(_Fn&& __f) &&
	{
	  using _Up = __expected::__result0<_Fn>;
	  static_assert(__expected::__is_expected<_Up>);
	  static_assert(is_same_v<typename _Up::error_type, _Er>);

	  if (has_value())
	    return std::__invoke(std::forward<_Fn>(__f));
	  else
	    return _Up(unexpect, std::move(_M_unex));
	}

       template<typename _Fn> requires is_constructible_v<_Er, const _Er>
	constexpr auto
	and_then(_Fn&& __f) const &&
	{
	  using _Up = __expected::__result0<_Fn>;
	  static_assert(__expected::__is_expected<_Up>);
	  static_assert(is_same_v<typename _Up::error_type, _Er>);

	  if (has_value())
	    return std::__invoke(std::forward<_Fn>(__f));
	  else
	    return _Up(unexpect, std::move(_M_unex));
	}

      template<typename _Fn>
	constexpr auto
	or_else(_Fn&& __f) &
	{
	  using _Gr = __expected::__result<_Fn, _Er&>;
	  static_assert(__expected::__is_expected<_Gr>);
	  static_assert(is_same_v<typename _Gr::value_type, _Tp>);

	  if (has_value())
	    return _Gr();
	  else
	    return std::__invoke(std::forward<_Fn>(__f), _M_unex);
	}

      template<typename _Fn>
	constexpr auto
	or_else(_Fn&& __f) const &
	{
	  using _Gr = __expected::__result<_Fn, const _Er&>;
	  static_assert(__expected::__is_expected<_Gr>);
	  static_assert(is_same_v<typename _Gr::value_type, _Tp>);

	  if (has_value())
	    return _Gr();
	  else
	    return std::__invoke(std::forward<_Fn>(__f), _M_unex);
	}

      template<typename _Fn>
	constexpr auto
	or_else(_Fn&& __f) &&
	{
	  using _Gr = __expected::__result<_Fn, _Er&&>;
	  static_assert(__expected::__is_expected<_Gr>);
	  static_assert(is_same_v<typename _Gr::value_type, _Tp>);

	  if (has_value())
	    return _Gr();
	  else
	    return std::__invoke(std::forward<_Fn>(__f), std::move(_M_unex));
	}

      template<typename _Fn>
	constexpr auto
	or_else(_Fn&& __f) const &&
	{
	  using _Gr = __expected::__result<_Fn, const _Er&&>;
	  static_assert(__expected::__is_expected<_Gr>);
	  static_assert(is_same_v<typename _Gr::value_type, _Tp>);

	  if (has_value())
	    return _Gr();
	  else
	    return std::__invoke(std::forward<_Fn>(__f), std::move(_M_unex));
	}

      template<typename _Fn> requires is_constructible_v<_Er, _Er&>
	constexpr auto
	transform(_Fn&& __f) &
	{
	  using _Up = __expected::__result0_xform<_Fn>;
	  using _Res = expected<_Up, _Er>;

	  if (has_value())
	    return _Res(__in_place_inv{}, std::forward<_Fn>(__f));
	  else
	    return _Res(unexpect, _M_unex);
	}

      template<typename _Fn> requires is_constructible_v<_Er, const _Er&>
	constexpr auto
	transform(_Fn&& __f) const &
	{
	  using _Up = __expected::__result0_xform<_Fn>;
	  using _Res = expected<_Up, _Er>;

	  if (has_value())
	    return _Res(__in_place_inv{}, std::forward<_Fn>(__f));
	  else
	    return _Res(unexpect, _M_unex);
	}

      template<typename _Fn> requires is_constructible_v<_Er, _Er>
	constexpr auto
	transform(_Fn&& __f) &&
	{
	  using _Up = __expected::__result0_xform<_Fn>;
	  using _Res = expected<_Up, _Er>;

	  if (has_value())
	    return _Res(__in_place_inv{}, std::forward<_Fn>(__f));
	  else
	    return _Res(unexpect, std::move(_M_unex));
	}

      template<typename _Fn> requires is_constructible_v<_Er, const _Er>
	constexpr auto
	transform(_Fn&& __f) const &&
	{
	  using _Up = __expected::__result0_xform<_Fn>;
	  using _Res = expected<_Up, _Er>;

	  if (has_value())
	    return _Res(__in_place_inv{}, std::forward<_Fn>(__f));
	  else
	    return _Res(unexpect, std::move(_M_unex));
	}

      template<typename _Fn>
	constexpr auto
	transform_error(_Fn&& __f) &
	{
	  using _Gr = __expected::__result_xform<_Fn, _Er&>;
	  using _Res = expected<_Tp, _Gr>;

	  if (has_value())
	    return _Res();
	  else
	    return _Res(__unexpect_inv{}, [&]() {
			  return std::__invoke(std::forward<_Fn>(__f),
					       _M_unex);
			});
	}

      template<typename _Fn>
	constexpr auto
	transform_error(_Fn&& __f) const &
	{
	  using _Gr = __expected::__result_xform<_Fn, const _Er&>;
	  using _Res = expected<_Tp, _Gr>;

	  if (has_value())
	    return _Res();
	  else
	    return _Res(__unexpect_inv{}, [&]() {
			  return std::__invoke(std::forward<_Fn>(__f),
					       _M_unex);
			});
	}

      template<typename _Fn>
	constexpr auto
	transform_error(_Fn&& __f) &&
	{
	  using _Gr = __expected::__result_xform<_Fn, _Er&&>;
	  using _Res = expected<_Tp, _Gr>;

	  if (has_value())
	    return _Res();
	  else
	    return _Res(__unexpect_inv{}, [&]() {
			  return std::__invoke(std::forward<_Fn>(__f),
					       std::move(_M_unex));
			});
	}

      template<typename _Fn>
	constexpr auto
	transform_error(_Fn&& __f) const &&
	{
	  using _Gr = __expected::__result_xform<_Fn, const _Er&&>;
	  using _Res = expected<_Tp, _Gr>;

	  if (has_value())
	    return _Res();
	  else
	    return _Res(__unexpect_inv{}, [&]() {
			  return std::__invoke(std::forward<_Fn>(__f),
					       std::move(_M_unex));
			});
	}

      // equality operators

      template<typename _Up, typename _Er2>
	requires is_void_v<_Up>
	  && requires (const _Er& __e, const _Er2& __e2) {
	    { __e == __e2 } -> convertible_to<bool>;
	  }
	friend constexpr bool
	operator==(const expected& __x, const expected<_Up, _Er2>& __y)
	noexcept(noexcept(bool(__x.error() == __y.error())))
	{
	  if (__x.has_value())
	    return __y.has_value();
	  else
	    return !__y.has_value() && bool(__x.error() == __y.error());
	}

      template<typename _Er2>
	requires requires (const _Er& __e, const _Er2& __e2) {
	  { __e == __e2 } -> convertible_to<bool>;
	}
	friend constexpr bool
	operator==(const expected& __x, const unexpected<_Er2>& __e)
	noexcept(noexcept(bool(__x.error() == __e.error())))
	{ return !__x.has_value() && bool(__x.error() == __e.error()); }

      friend constexpr void
      swap(expected& __x, expected& __y)
      noexcept(noexcept(__x.swap(__y)))
      requires requires { __x.swap(__y); }
      { __x.swap(__y); }

    private:
      template<typename, typename> friend class expected;

      template<typename _Vp>
	constexpr void
	_M_assign_unex(_Vp&& __v)
	{
	  if (_M_has_value)
	    {
	      std::construct_at(__builtin_addressof(_M_unex),
				std::forward<_Vp>(__v));
	      _M_has_value = false;
	    }
	  else
	    _M_unex = std::forward<_Vp>(__v);
	}

      using __in_place_inv = __expected::__in_place_inv;
      using __unexpect_inv = __expected::__unexpect_inv;

      template<typename _Fn>
	explicit constexpr
	expected(__in_place_inv, _Fn&& __fn)
	: _M_void(), _M_has_value(true)
	{ std::forward<_Fn>(__fn)(); }

      template<typename _Fn>
	explicit constexpr
	expected(__unexpect_inv, _Fn&& __fn)
	: _M_unex(std::forward<_Fn>(__fn)()), _M_has_value(false)
	{ }

      union {
	struct { } _M_void;
	_Er _M_unex;
      };

      bool _M_has_value;
    };
  /// @}

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std

#endif // __cpp_lib_expected
#endif // _GLIBCXX_EXPECTED
